/*
JavaScript 的对象（Object），本质上是键值对的集合（Hash 结构），
但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
为了解决这个问题，ES6 提供了 Map 数据结构。它类似于对象，也是键值对的集合，
但是“键”的范围不限于字符串，各种类型的值（包括对象）都可以当作键。
也就是说，Object 结构提供了“字符串—值”的对应，Map 结构提供了“值—值”的对应，是一种更完善的 Hash 结构实现。
如果你需要“键值对”的数据结构，Map 比 Object 更合适。
*/

const m = new Map();
const o = { p: 'Hello World' };

m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false

const map = new Map([
    ['name', '张三'],
    ['title', 'Author']
]);

map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"

//set和map结合
const set = new Set([
    ['foo', 1],
    ['bar', 2]
]);
const m1 = new Map(set);
m1.get('foo') // 1

const m2 = new Map([['baz', 3]]);
const m3 = new Map(m2);
m3.get('baz') // 3

//如果对同一个键多次赋值，后面的值将覆盖前面的值。
//set方法返回的是当前的Map对象，因此可以采用链式写法。
map
    .set(1, 'aaa')
    .set(1, 'bbb');

console.log(map.get(1)) // "bbb"
//如果读取一个未知的键，则返回undefined。

map.set(['a'], 555);
map.get(['a']) // undefined
//上面代码的set和get方法，表面是针对同一个键，
//但实际上这是两个不同的数组实例，内存地址是不一样的，因此get方法无法读取该键，返回undefined。

//Map.prototype.set(key, value)
//set方法设置键名key对应的键值为value，然后返回整个 Map 结构。如果key已经有值，则键值会被更新，否则就新生成该键。
const m4 = new Map();

m4.set('edition', 6)        // 键是字符串
m4.set(262, 'standard')     // 键是数值
m4.set(undefined, 'nah')    // 键是 undefined
//get方法读取key对应的键值，如果找不到key，返回undefined。
const hello = function () { console.log('hello'); };
m4.set(hello, 'Hello ES6!') // 键是函数

m4.get(hello)  // Hello ES6!
m.has('years')       // false
m.has(hello)           // true
m4.has(undefined)     // true
//delete()方法删除某个键，返回true。如果删除失败，返回false
m4.delete(undefined) //true
m4.delete(undefined) // false
//clear()方法清除所有成员，没有返回值。
m.clear()

/*
    Map 结构原生提供三个遍历器生成函数和一个遍历方法。

    Map.prototype.keys()：返回键名的遍历器。
    Map.prototype.values()：返回键值的遍历器。
    Map.prototype.entries()：返回所有成员的遍历器。
    Map.prototype.forEach()：遍历 Map 的所有成员
    需要特别注意的是，Map 的遍历顺序就是插入顺序
*/

const map1 = new Map([
    ['F', 'no'],
    ['T', 'yes'],
]);

for (let key of map1.keys()) {
    console.log(key);
}
// "F"
// "T"

for (let value of map1.values()) {
    console.log(value);
}
// "no"
// "yes"

for (let item of map1.entries()) {
    console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"

// 或者
for (let [key, value] of map1.entries()) {
    console.log(key, value);
}
// "F" "no"
// "T" "yes"

// 等同于使用map.entries()
for (let [key, value] of map1) {
    console.log(key, value);
}
// "F" "no"
// "T" "yes"

//Map 结构转为数组结构，比较快速的方法是使用扩展运算符（...）
const map2 = new Map([
    [1, 'one'],
    [2, 'two'],
    [3, 'three'],
]);
console.log([...map2.keys()])// [1, 2, 3]
console.log([...map2.values()])// ['one', 'two', 'three']

console.log([...map2.entries()])// [[1,'one'], [2, 'two'], [3, 'three']]

console.log([...map2])//[ [ 1, 'one' ], [ 2, 'two' ], [ 3, 'three' ] ]

//Map 结构的默认遍历器接口（Symbol.iterator属性），就是entries方法
console.log(map[Symbol.iterator] === map.entries)//true

